//
// Created by francklinson on 2021/7/11 AT 23:38.
//
#include <vector>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

class Solution {
private:
    vector<vector<int>> edges; //邻接表
    vector<int> visited;       // 访问记录  0 未搜索 1搜索中 2搜索完成
    bool valid = true;         // 是否存在环
    vector<int> courseOrder;   // 结果数组
public:
    vector<int> findOrder(int numCourses, vector<vector<int>> &prerequisites) {
        edges.resize(numCourses);
        visited.resize(numCourses);
        for (const auto &info:prerequisites) {
            edges[info[1]].push_back(info[0]);// 每门课程的后导课程
        }
        for (int i = 0; i < numCourses && valid; ++i) {
            if (visited[i] == 0) { // 没访问过的课程
                dfs(i);
            }
        }
        if (!valid) return {};
        reverse(courseOrder.begin(), courseOrder.end());
        return courseOrder;
    }

    void dfs(int u) {
        // 将节点标记为「搜索中」
        visited[u] = 1;
        // 搜索其相邻节点
        // 只要发现有环，立刻停止搜索
        for (int v: edges[u]) {
            // 如果「未搜索」那么搜索相邻节点
            if (visited[v] == 0) {
                dfs(v);
                if (!valid) {
                    return;
                }
            }
                // 如果「搜索中」说明找到了环
            else if (visited[v] == 1) {
                valid = false;
                return;
            }
        }
        // 将节点标记为「已完成」
        visited[u] = 2;
        // 将节点入栈
        courseOrder.push_back(u);
    }

};
class Solution2 { // bfs
private:
    // 存储有向图
    vector<vector<int>> edges;
    // 存储每个节点的入度
    vector<int> indeg;
    // 存储答案
    vector<int> result;

public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        indeg.resize(numCourses);
        for (const auto& info: prerequisites) {
            edges[info[1]].push_back(info[0]); // 每个节点的出点
            ++indeg[info[0]];
        }

        queue<int> q;
        // 将所有入度为 0 的节点放入队列中
        for (int i = 0; i < numCourses; ++i) {
            if (indeg[i] == 0) {
                q.push(i);
            }
        }

        while (!q.empty()) {
            // 从队首取出一个节点
            int u = q.front();
            q.pop();
            // 放入答案中
            result.push_back(u);
            for (int v: edges[u]) {
                --indeg[v];
                // 如果相邻节点 v 的入度为 0，就可以选 v 对应的课程了
                if (indeg[v] == 0) {
                    q.push(v);
                }
            }
        }

        if (result.size() != numCourses) {
            return {};
        }
        return result;
    }
};


int main() {
    vector<vector<int>> prerequisites{{1, 0},
                                      {2, 0},
                                      {3, 1},
                                      {3, 2}};
    Solution solution;
    auto order = solution.findOrder(4, prerequisites);
    for (auto &x:order) cout << x << endl;
    return 0;
}

